﻿using Aliyun.Api.LOG;
using Aliyun.Api.LOG.Common.Utilities;
using Aliyun.Api.LOG.Data;
using Aliyun.Api.LOG.Request;
using Aliyun.Api.LOG.Response;
using AntJoin.Core.Common;
using System;
using System.Collections.Generic;
using System.Text;

namespace AntJoin.Log
{
    /// <summary>
    /// 日志读取
    /// </summary>
    public class LogReader
    {
        private const string appKey = "LTAITZcbbEa6lv1O";
        private const string appSecret = "AxC5GgB9Vml3CxgEH0wxnnfj52JxCm";

        public T GetLog<T>(OperationalTopic topic, string query, DateTime startTime, DateTime endTime) where T : LogEntityBase
        {
            List<T> Logs = GetLogs<T>(topic, query, startTime, endTime, 1, 1);

            if (Logs != null && Logs.Count > 0)
            {
                return Logs[0];
            }
            else
            {
                return default(T);
            }
        }

        public List<T> GetLogs<T>(OperationalTopic topic, string query, DateTime startTime, DateTime endTime, int page, int pageSize) where T : LogEntityBase
        {
            GetLogsRequest request = new GetLogsRequest()
            {
                Topic = topic.ToString(),
                From = LogCommon.UnixTimeSpan(startTime),
                To = LogCommon.UnixTimeSpan(endTime),
                Logstore = LogCommon.config.GetValue(LogCommon.OperationalStoreName),
                Project = LogCommon.config.GetValue(LogCommon.ProjectName),
                Reverse = true,
                Lines = pageSize,
                Offset = (page - 1) * pageSize,
                Query = query
            };
            LogClient client = new LogClient(LogCommon.config.GetValue(LogCommon.Endpoint), appKey, appSecret);
            GetLogsResponse response = client.GetLogs(request);
            if (response.Count > 0)
            {
                return ConvertLogData<T>(response.Logs);
            }
            else
            {
                return null;
            }
        }
        public int GetLogCount(OperationalTopic topic, string query, DateTime startTime, DateTime endTime)
        {
            if (!string.IsNullOrEmpty(query))
            {
                query = string.Format("__topic__:{0} and {1} | select count(*)", topic.ToString(), query);
            }
            else
            {
                query = "*| select count(*)";
            }
            GetLogsRequest request = new GetLogsRequest()
            {
                Topic = topic.ToString(),
                From = LogCommon.UnixTimeSpan(startTime),
                To = LogCommon.UnixTimeSpan(endTime),
                Logstore = LogCommon.config.GetValue(LogCommon.OperationalStoreName),
                Project = LogCommon.config.GetValue(LogCommon.ProjectName),
                Reverse = true,
                Query = query
            };
            LogClient client = new LogClient(LogCommon.config.GetValue(LogCommon.Endpoint), appKey, appSecret);
            GetLogsResponse response = client.GetLogs(request);
            if (response.Count > 0)
            {
                return int.Parse(response.Logs[0].Contents[0].Value);
            }
            return 0;
        }

        public List<T> GetLogResult<T>(OperationalTopic topic, string query, DateTime startTime, DateTime endTime) where T : class
        {
            if (!string.IsNullOrEmpty(query))
            {
                query = string.Format("__topic__:{0} and {1}", topic.ToString(), query);
            }
            GetLogsRequest request = new GetLogsRequest()
            {
                Topic = topic.ToString(),
                From = LogCommon.UnixTimeSpan(startTime),
                To = LogCommon.UnixTimeSpan(endTime),
                Logstore = LogCommon.config.GetValue(LogCommon.OperationalStoreName),
                Project = LogCommon.config.GetValue(LogCommon.ProjectName),
                Reverse = true,
                Query = query
            };
            LogClient client = new LogClient(LogCommon.config.GetValue(LogCommon.Endpoint), appKey, appSecret);
            GetLogsResponse response = client.GetLogs(request);
            if (response.Count > 0)
            {
                return ConvertLogResult<T>(response.Logs);
            }
            else
            {
                return null;
            }
        }

        private List<T> ConvertLogResult<T>(List<QueriedLog> logs)
        {
            List<T> LogData = new List<T>();
            Type type = typeof(T);
            foreach (var d in logs)
            {
                T t = Activator.CreateInstance<T>();
                ConvertLogContent<T>(type, d.Contents, ref t);
                LogData.Add(t);
            }
            return LogData;
        }

        private List<T> ConvertLogData<T>(List<QueriedLog> logs) where T : LogEntityBase
        {
            List<T> LogData = new List<T>();
            Type type = typeof(T);
            foreach (var d in logs)
            {
                T t = Activator.CreateInstance<T>();
                t.Time = DateUtils.GetDateTime(d.Time);
                ConvertLogContent<T>(type, d.Contents, ref t);
                LogData.Add(t);
            }
            return LogData;
        }

        private void ConvertLogContent<T>(Type type, List<LogContent> logContent, ref T t)
        {
            foreach (var i in logContent)
            {
                object value = null;
                var property = type.GetProperty(i.Key);
                if (property != null && property.CanWrite && !string.IsNullOrEmpty(i.Value))
                {
                    if (string.IsNullOrEmpty(i.Value) || i.Value == "null")
                    {
                        value = null;
                    }
                    else if (property.PropertyType == typeof(string))
                    {
                        value = i.Value;
                    }
                    else if (property.PropertyType == typeof(int) || property.PropertyType == typeof(Nullable<int>))
                    {
                        value = int.Parse(i.Value);
                    }
                    else if (property.PropertyType == typeof(decimal) || property.PropertyType == typeof(Nullable<decimal>))
                    {
                        value = decimal.Parse(i.Value);
                    }
                    else if (property.PropertyType == typeof(double) || property.PropertyType == typeof(Nullable<double>))
                    {
                        value = double.Parse(i.Value);
                    }
                    else if (property.PropertyType == typeof(bool) || property.PropertyType == typeof(Nullable<bool>))
                    {
                        value = bool.Parse(i.Value);
                    }
                    else if (property.PropertyType == typeof(TimeSpan) || property.PropertyType == typeof(Nullable<TimeSpan>))
                    {
                        value = TimeSpan.Parse(i.Value);
                    }
                    property.SetValue(t, value, null);
                }
            }
        }
    }
}
